package com.neasho.neashoadminv1.web.service.sys

import com.neasho.neashoadminv1.infrastructure.domain.sys.SysMenu
import com.neasho.neashoadminv1.infrastructure.domain.sys.parentId
import com.neasho.neashoadminv1.infrastructure.dto.sys.*
import org.babyfish.jimmer.Specification
import org.babyfish.jimmer.View
import org.babyfish.jimmer.spring.repository.fetchSpringPage
import org.babyfish.jimmer.spring.repository.orderBy
import org.babyfish.jimmer.sql.ast.mutation.AssociatedSaveMode
import org.babyfish.jimmer.sql.ast.mutation.SaveMode
import org.babyfish.jimmer.sql.kt.KSqlClient
import org.babyfish.jimmer.sql.kt.ast.expression.eq
import org.babyfish.jimmer.sql.kt.ast.mutation.KDeleteResult
import org.babyfish.jimmer.sql.kt.ast.mutation.KSimpleSaveResult
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import kotlin.reflect.KClass

@Service
class SysMenuService(
    private val sqlClient: KSqlClient,
) {
    val log: Logger = LoggerFactory.getLogger(SysMenuService::class.java)

    private val entityClass = SysMenu::class

    fun <V : View<SysMenu>> page(spec: Specification<SysMenu>, viewType: KClass<V>, pageable: Pageable): Page<V> {
        return sqlClient.createQuery(entityClass) {
            where(spec)
            orderBy(pageable.sort)
            select(table.fetch(viewType))
        }.fetchSpringPage(pageable)
    }

    fun save(input: SysMenuAddInput): KSimpleSaveResult<SysMenu> {
        return sqlClient.save(input)
    }

    fun update(input: SysMenuAddInput): KSimpleSaveResult<SysMenu> {
        return sqlClient.save(input)
    }

    fun deleteByPhysical(id: Long): KDeleteResult {
        return sqlClient.deleteById(entityClass, id)
    }

    fun batchDeleteByIds(ids: List<Long>): KDeleteResult {
        return sqlClient.deleteByIds(entityClass, ids)
    }

    fun <V:View<SysMenu>> findById(spec: SysMenuDetailSpec, viewType: KClass<V>) : V? {
        return sqlClient.executeQuery(entityClass) {
            where(spec)
            select(table.fetch(viewType))
        }.firstOrNull()
    }

    fun <V:View<SysMenu>> list(spec: SysMenuListSpec, viewType: KClass<V>) : List<V> {
        return sqlClient.executeQuery(entityClass) {
            where(spec)
            select(table.fetch(viewType))
        }
    }

    @Transactional
    fun batchUpdate(list: List<SysMenuUpdateInput>) : Int {
        return sqlClient.entities.saveInputs(list, SaveMode.UPDATE_ONLY, AssociatedSaveMode.REPLACE).totalAffectedRowCount
    }

    @Transactional
    fun batchSave(list: List<SysMenuAddInput>) : Int {
        return sqlClient.entities.saveInputs(list, SaveMode.INSERT_ONLY, AssociatedSaveMode.REPLACE).totalAffectedRowCount
    }

    fun <V:View<SysMenu>> tree(spec: SysMenuListSpec, viewType: KClass<V>): List<V> {
        return sqlClient.executeQuery(entityClass) {
            where(spec)
            where(table.parentId `eq` 0)
            select(table.fetch(viewType))
        }
    }

}